import 'assets/style/editor.scss'
import ast from '!!html-ast-loader!./index.html'

import RteConfig, { RteUserConfig } from './config'
import { GrteMoniterMap, RteRefs, RteSelector } from './declare'
import { ElementListener, RenderInst } from 'share/declare'
import render from 'share/render'
import { delFragment, getFragment, setFragment } from 'share/fragment'
import RteMenu from 'menu/index'
import RteIcon from './icon'
import { reactive, ReactiveInstance } from 'share/reactive'
import { Moniter } from 'share/moniter'
import initialize from './initialize-logic/initialize'
import RteContent from 'content/index'
import RteInput from 'input/input'
import RteSelection from 'selection/selection'
import RteMouse from 'selection/mouse'

const SELECTOR: WeakMap<Rte, RteSelector> = new WeakMap()

export default class Rte implements RenderInst {
  /**
   * 双向绑定的数据
   */
  public $data: ReactiveInstance<RteConfig> = reactive()

  /**
   * 注册的 HTMLElement 节点
   */
  // @ts-ignore
  public $refs: RteRefs = {}

  /**
   * 发布订阅事件
   */
  public $moniter: Moniter<GrteMoniterMap> = new Moniter()

  /**
   * HTML 的 addEventListener 回调函数
   */
  public $listener: ElementListener<Rte> = {}

  public config: RteConfig

  public menu: RteMenu

  public icon: RteIcon

  public content: RteContent

  public input: RteInput

  public selection: RteSelection

  public mouse: RteMouse

  public constructor(config?: RteUserConfig) {
    this.config = new RteConfig()
    config && Object.assign(this.config, config)

    initialize(this)

    // 缓存生成好的 DOM 树（依赖 $data、$moniter、$listener）
    setFragment(this, render(ast, this))

    // 依赖 DOM 树，所以在 render 后面初始化
    this.icon = new RteIcon()
    this.menu = new RteMenu(this)
    this.content = new RteContent(this)
    this.input = new RteInput(this)
    this.selection = new RteSelection(this)
    this.mouse = new RteMouse(this)

    this.$moniter.$emit('created', null)
  }

  /**
   * 设置/获取编辑器的容器节点
   * @param rootSelector 编辑器的容器节点
   * @param toolbarSelector 编辑器 toolbar 的容器节点
   * @returns
   */
  public selector(rootSelector?: string | HTMLElement, toolbarSelector?: string | HTMLElement) {
    if (!rootSelector) return SELECTOR.get(this) || null

    const selector = rootSelector instanceof HTMLElement ? rootSelector : document.querySelector(rootSelector)

    if (!selector) return null

    const temp: RteSelector = { root: selector as HTMLElement, toolbar: null }
    SELECTOR.set(this, temp)

    if (toolbarSelector) {
      const toolbar = typeof toolbarSelector === 'string' ? document.querySelector(toolbarSelector) : toolbarSelector
      toolbar && (temp.toolbar = toolbar as HTMLElement)
    }
    return temp
  }

  /**
   * 将编辑器绑定到 DOM 树中
   */
  public $mount(rootSelector?: string | HTMLElement, toolbarSelector?: string | HTMLElement) {
    this.$data.$defines(this.config)
    this.$moniter.$emit('mount', null)

    const frag = getFragment(this)
    if (frag) {
      const selector = this.selector(rootSelector, toolbarSelector)
      if (selector) {
        delFragment(this)

        selector.toolbar && selector.toolbar.append(this.$refs.toolbar)

        selector.root.append(frag)

        this.$moniter.$emit('mounted', null)
      }
    }
  }

  public $unmount() {}
}
